# -*- coding: utf-8 -*-
"""
Module Description: 接口基类
Date:2016/11/08
Anchor:Bai Jin Ping
"""
import sys
from time import time

import utils.json_utils as json
from app.user.component.core.component_center import ComponentCenter
from common import service_config
from framework.firefly_dc.global_errcode import GlobalErrCode


class BaseAction(object):
    """接口基类"""

    # 接口返回时, 返回数据res经过str()处理后保存到接口日志response字段的最大程度
    # 默认为-1, 不限制保存长度
    # 对于轮询接口或者价值不大的返回, 可以设置LOG_LEN来减少日志存储量
    LOG_LEN = -1

    # 该属性表示接口是否能够在传入的(appid,serverid)对应区服处于关服状态时访问
    # 若设置为True,则要求接口内部逻辑需要自行设置appid/serverid, 或者接口内部逻辑不涉及db访问
    # 业务逻辑接口不能设置为True, 仅少数后台管理接口允许设置为True
    can_call_when_server_stat_offline = False

    # 默认版本号
    default_ver = service_config.VersionControl.min_compatible_client_ver()

    # 接口号
    action_id = 0

    # 组件中心对象
    cc = ComponentCenter()

    def __init__(self, args):
        # 客户端请求参数字典(所有key为小写)
        self.args = args
        # 状态码
        self.status_code = GlobalErrCode.SUCCESS
        # 返回数据的描述文本
        self.info = ''
        # 返回数据的字典
        self.response = {}
        # action 解析的参数字典
        self.action_parse_args = {}
        # 返回头数据
        self.headers = {}

    def parse_arguments(self):
        """参数解析函数"""
        return True
        
    def do_action(self):
        """用于统一处理:result,data这种返回格式"""
        return True, {}

    def take_action(self):
        """业务逻辑处理函数
        """
        result, data = self.do_action()
        if result:
            self.add_response_dict(data)
        else:
            self.set_error(data)
        return result

    def before_action(self):
        """接口入口函数,最先调用"""
        return True
    
    def after_action(self):
        """接口响应后处理,记录日志等"""
        return True

    def get_response(self):
        """取得响应数据
        """
        if not self.response.has_key('Stat'):
            self.add_response('Stat', self.status_code)
        if not self.response.has_key('Info'):
            self.add_response('Info', self.info)
        self.add_response('ActionId', self.action_id)
        return self.response

    def add_response(self, key, value):
        """
        添加响应数据
        :param key: 键
        :param value: 值
        """
        self.response[key] = value
    
    def add_response_dict(self, d):
        """
        批量添加响应数据
        :param d: dict格式的返回数据
        """
        self.response.update(d)

    def set_error(self, info_name, stat=GlobalErrCode.FAILED):
        """错误请求响应数据
        :param info_name: 错误提示的变量名
        :param stat: 状态码
        """
        self.info = info_name
        self.status_code = stat

    def is_error(self):
        """是否是错误请求
        """
        return self.status_code != GlobalErrCode.SUCCESS

    def has_param(self, key):
        """参数是否存在
        """
        return key.lower() in self.args or hasattr(self, key)

    def get_str(self, key, default=None, validate=None):
        """取得str参数
        :param key: 键
        :return: 参数是否存在
        """
        val = self.args.get(key.lower(), default)
        if val is None:
            return False

        if validate and not validate(val):
            return False

        setattr(self, key, str(val))
        self.action_parse_args[key] = str(val)
        return self.has_param(key)

    def get_int(self, key, default=None, mini=0, maxi=sys.maxsize, validate=None):
        """取得int参数
        :param key: 键
        :param default: 默认值
        :param mini: 最小值
        :param maxi: 最大值
        :return: 参数是否存在
        """
        val = self.args.get(key.lower(), default)
        if val is None:
            return False

        if isinstance(val, str):
            val = val.split('.')[0]

        try:
            setattr(self, key, int(val))
            self.action_parse_args[key] = int(val)
        except ValueError:
            return False
        value = getattr(self, key)
        if value < mini or value > maxi:
            return False

        if validate and not validate(value):
            return False

        return self.has_param(key)

    def get_float(self, key, default=None, min=0.0, max=9999999999.0):
        """
        取得float参数
        """
        val = self.args.get(key.lower(), default)
        if val is None:
            return False

        try:
            float_val = float(val)
        except ValueError:
            return False
        setattr(self, key, float_val)
        self.action_parse_args[key] = float_val
        if min > float_val or max < float_val:
            return False

        return self.has_param(key)

    def get_json(self, key, default=None, need_dict=False, validate=None):
        """
        取得json格式参数
        :param key: 键
        :param default: 默认值
        :param need_dict:是否需要强制转换为dict
        """
        try:
            lkey = key.lower()
            json_data = json.loads(self.args.get(lkey)) if self.has_param(lkey) else default
            if need_dict and not isinstance(json_data, dict):
                json_data = dict(json_data)
            if validate and not validate(json_data):
                return False
            setattr(self, key, json_data)
            if json_data is not None:
                self.action_parse_args[key] = json_data
            return self.has_param(key)
        except (TypeError, ValueError):
            return False

    def get_datetime(self, key, validate=None):
        """
        取得日期时间格式的参数
        :param key:键
        :return:
        """
        from utils.time_utils import checkStrIsDatetime, strToDatetime

        if not self.get_str(key):
            return False

        datetime_args = getattr(self, key)
        if not checkStrIsDatetime(datetime_args):
            return False

        dt = strToDatetime(datetime_args)
        if validate and not validate(dt):
            return False

        setattr(self, key, dt)
        self.action_parse_args[key] = dt
        return True

    def get_date(self, key):
        """
        取得日期格式的参数
        :param key:键
        :return:
        """
        from utils.time_utils import checkStrIsDate, strToDate

        if not self.get_str(key):
            return False

        date_args = getattr(self, key)
        if not checkStrIsDate(date_args):
            return False

        setattr(self, key, strToDate(date_args))
        self.action_parse_args[key] = strToDate(date_args)
        return True

    def set_headers(self, key, value):
        """
        设置返回头数据
        :param key:
        :param value:
        :return:
        """
        self.headers[key] = value

    def get_headers(self):
        """
        返回 返回头的数据
        :return:
        """
        return self.headers


def _process_time(begin_time, end_time):
    """
    根据处理开始时间和结束时间计算出处理时间
    :param begin_time: datetime
    :param end_time: datetime
    :return: process_time(ms)
    """
    return (end_time - begin_time) * 1000


class AuthAction(BaseAction):
    """授权校验的接口
    """
    def __init__(self, args):
        BaseAction.__init__(self, args)
        self.rid = 'default'

    def before_action(self):
        if self.get_str('rid'):
            return True
        return False


class AuthLogAction(AuthAction):
    """
    授权校验和记录日志的接口
    """

    def __init__(self, args):
        AuthAction.__init__(self, args)
        self.begin_time = time()
        # end_time的实际赋值在action_service调用完接口之后赋值的
        self.end_time = self.begin_time

    def after_action(self):
        LogAction.change_args_before_logging(self.args, add_del_attr=['rid', 'actionid'])

        # if self.LOG_LEN == -1:
        #     NonCoreLogProxy.act(
        #         role_id=self.rid, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape').replace('\'', '\"'),
        #         proc_time=_process_time(self.begin_time, self.end_time),
        #         begin_time=self.begin_time,
        #         reserve={"Ip": self.args.get("ip", ""),
        #                  "ClientTime": int(self.args.get("clienttime")),
        #                  "GatewayTime": int(self.args.get("gatewaytime")),
        #                  "Lang": self.args.get("lang", "zh-cn"),
        #                  "Code": self.status_code}
        #     )
        # else:
        #     NonCoreLogProxy.act(
        #         role_id=self.rid, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape')[:self.LOG_LEN].replace('\'', '\"'),
        #         proc_time=_process_time(self.begin_time, self.end_time),
        #         begin_time=self.begin_time,
        #         reserve={"Ip": self.args.get("ip", ""),
        #                  "ClientTime": int(self.args.get("clienttime")),
        #                  "GatewayTime": int(self.args.get("gatewaytime")),
        #                  "Lang": self.args.get("lang", "zh-cn"),
        #                  "Code": self.status_code}
        #     )


class LogAction(BaseAction):
    """
    没有授权校验的日志接口
    """

    # 请求参数中要移除的字段
    args_log_del_attr = ['sid', 'actionid']

    def __init__(self, args):
        BaseAction.__init__(self, args)
        self.begin_time = time()
        self.end_time = self.begin_time

    @staticmethod
    def change_args_before_logging(args, add_del_attr=None):
        """
        移除不需要记录到日志的字段

        :param args: 参数字典
        :param add_del_attr: 新增的需要移除的参数key
        """
        if add_del_attr is None:
            add_del_attr = []

        for k in args.keys():
            if k in LogAction.args_log_del_attr or k in add_del_attr:
                del args[k]

    def after_action(self):
        self.change_args_before_logging(self.args)
        # if self.LOG_LEN == -1:
        #     NonCoreLogProxy.act(
        #         role_id='action', act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape').replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )
        # else:
        #     NonCoreLogProxy.act(
        #         role_id='action', act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape')[:self.LOG_LEN].replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )


class LogAdmin(LogAction):
    """
    管理后台日志接口
    """
    def after_action(self):
        LogAction.change_args_before_logging(self.args)
        opr = 'admin'
        if self.args.get('CrossServer'.lower(), 0):
            opr = 'CrossServer'
        # if self.LOG_LEN == -1:
        #     NonCoreLogProxy.act(
        #         role_id=opr, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape').replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )
        # else:
        #     NonCoreLogProxy.act(
        #         role_id=opr, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape')[:self.LOG_LEN].replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )


class LogPayment(LogAction):
    """
    支付中心日志接口
    """
    def get_response(self):
        """
        取得响应数据
        """
        if 'Stat' not in self.response:
            self.add_response('Stat', self.status_code)
        if 'Info' not in self.response:
            self.add_response('Info', self.info)
        self.add_response('ActionId', self.action_id)
        return self.response

    def after_action(self):
        LogAction.change_args_before_logging(self.args)

        # if self.LOG_LEN == -1:
        #     NonCoreLogProxy.act(
        #         role_id='payment', act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape').replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )
        # else:
        #     NonCoreLogProxy.act(
        #         role_id='payment', act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape')[:self.LOG_LEN].replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )


class LogCross(LogAction):
    """
     跨服日志接口
    """
    def after_action(self):
        LogAction.change_args_before_logging(self.args)
        opr = 'Cross'
        # if self.LOG_LEN == -1:
        #     NonCoreLogProxy.act(
        #         role_id=opr, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape').replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )
        # else:
        #     NonCoreLogProxy.act(
        #         role_id=opr, act_id=self.action_id.__str__(), act_stat=self.status_code,
        #         req=str(self.args).encode('unicode_escape').replace('\'', '\"'),
        #         res=str(self.response).encode('unicode_escape')[:self.LOG_LEN].replace('\'', '\"'),
        #         begin_time=self.begin_time,
        #         proc_time=_process_time(self.begin_time, self.end_time)
        #     )


if __name__ == '__main__':
    args = {
        'did': '[]'
    }

    action = BaseAction(args)
    print action.get_int('uid', default=0)
    print action.get_json('id', default=0)
    pass

